package com.yanboot.iot;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson2.JSONObject;
import com.yanboot.iot.core.constant.TransportProtocol;
import com.yanboot.iot.core.message.device.DeviceMessage;
import com.yanboot.iot.core.message.device.impl.ReportEventMessage;
import com.yanboot.iot.core.message.device.impl.ReportPropertyMessage;
import com.yanboot.iot.core.message.protocol.ProtocolMessage;
import com.yanboot.iot.core.message.protocol.impl.TcpProtocolMessage;
import com.yanboot.iot.core.operator.OperatorSupplier;
import com.yanboot.iot.core.session.DeviceSession;
import com.yanboot.iot.sdk.protocol.MessageExporter;
import com.yanboot.iot.sdk.protocol.ProtocolCodec;
import com.yanboot.iot.sdk.protocol.ProtocolFeature;
import com.yanboot.iot.sdk.protocol.ProtocolSupport;
import com.yanboot.iot.utils.gb26875.enums.PacketElement;
import com.yanboot.iot.utils.gb26875.exception.GB26875Exception;
import com.yanboot.iot.utils.gb26875.format.GB26875Mapper;
import com.yanboot.iot.utils.gb26875.utils.AsciiUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;

public class WenJingTcpCodec implements ProtocolCodec {

    private static final Logger log = LoggerFactory.getLogger(WenJingTcpCodec.class);

    @Override
    public ProtocolSupport support() {
        return new ProtocolSupport(TransportProtocol.TCP)
                .id("wenjing-tcp-codec")
                .name("GB/T26875")
                .feature(new ProtocolFeature().keepOnline(true).keepOnlineTimeoutSeconds(300))
                .description("文景用传TCP(GB/T26875)协议");
    }

    @Override
    public void decode(OperatorSupplier supplier, DeviceSession deviceSession, ProtocolMessage<?> message, MessageExporter<DeviceMessage<?>> messageExporter) {
        TcpProtocolMessage message1 = (TcpProtocolMessage) message;
        ByteBuf payload = message1.payload();
        byte[] bytes = new byte[payload.readableBytes()];
        payload.readBytes(bytes);
        String s = AsciiUtil.bytes2HexString(bytes);
        log.info("GB/T26875解析数据:{}", s);
        byte[] bytes1 = AsciiUtil.hexString2Bytes(s);
        // 使用工具类解析
        try {
            Map<String, Object> map = new GB26875Mapper().readValue(bytes1, Map.class);
            Map<String, Object> data = (Map<String, Object>) map.get("data");
            log.info("GB/T26875解析data数据:{}", data);
            exporterMessage(map, messageExporter);
        } catch (IOException | GB26875Exception e) {
            throw new RuntimeException(e);
        }
        byte[] bytes2 = ackResponse(bytes1);
        log.info("GB/T26875响应数据:{}", AsciiUtil.bytes2HexString(bytes2));
        deviceSession.send(new TcpProtocolMessage()
                .payload(Unpooled.buffer().writeBytes(bytes2)));
    }

    private static void exporterMessage(Map<String, Object> map, MessageExporter<DeviceMessage<?>> messageExporter) {
        // 流水号
        Short flow = (Short) map.get("flow");
        // 协议版本号
        Short mainVersion = (Short) map.get("mainVersion");
        // 用户协议版本号
        Short minorVersion = (Short) map.get("minorVersion");
        // 消息上报时间
        LocalDateTime time = (LocalDateTime) map.get("time");
        // 源设备地址 作为网关设备ID
        String sourceAddress = (String) map.get("sourceAddress");
        sourceAddress = sourceAddress.replace(":", "");
        // 目的设备地址
        String targetAddress = (String) map.get("targetAddress");
        LinkedHashMap<String, Object> data = (LinkedHashMap<String, Object>) map.get("data");
        ArrayList msgData1 = (ArrayList) data.get("msgData");
        LinkedHashMap<String, Object> msgData = (LinkedHashMap<String, Object>) msgData1.getFirst();
        Short msgDataType = (Short) data.get("msgDataType");
        log.info("获取到的消息类型为：{}", msgDataType);
        switch (msgDataType) {
            case 2 -> {
                String s = (String) msgData.get("partDesc");
                String deviceId = (String) msgData.get("partAddress");
                LocalDateTime localDateTime = LocalDateTime.parse((String) msgData.get("happenTime"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                ReportPropertyMessage reportPropertyMessage = new ReportPropertyMessage();
                reportPropertyMessage.messageId(IdUtil.getSnowflakeNextIdStr());
                reportPropertyMessage.deviceId(deviceId);
                reportPropertyMessage.setProperties(JSONObject.parseObject(s));
                reportPropertyMessage.timestamp(localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli());
                messageExporter.export(reportPropertyMessage);
                log.info("id为:{}的设备上传了消息,{}", deviceId, s);
            }
            // 用户信息传输装置运行状态
            case 21 -> {
                String runningStatus = (String) msgData.get("runningStatus");
                JSONObject jsonObject = JSONObject.parseObject(runningStatus);
                ReportPropertyMessage message = new ReportPropertyMessage();
                message.setProperties(jsonObject);
                message.deviceId(sourceAddress);
                message.messageId(IdUtil.getSnowflakeNextIdStr());
                LocalDateTime localDateTime = LocalDateTime.parse((String) msgData.get("happenTime"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                message.timestamp(localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli());
                messageExporter.export(message);
            }
            // 用户信息传输装置操作信息
            case 24 -> {
                String s = (String) msgData.get("operateType");
                LocalDateTime localDateTime = LocalDateTime.parse((String) msgData.get("happenTime"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                ReportEventMessage reportEventMessage = new ReportEventMessage();
                reportEventMessage.addProperty("operateType", s);
                reportEventMessage.deviceId(sourceAddress);
                reportEventMessage.messageId(IdUtil.getSnowflakeNextIdStr());
                reportEventMessage.timestamp(localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli());
                messageExporter.export(reportEventMessage);
            }
            // 传用户信息传输装置系统时间
            case 28 -> {
                ReportPropertyMessage reportPropertyMessage = new ReportPropertyMessage();
                reportPropertyMessage.deviceId(sourceAddress.replace(":", ""));
                reportPropertyMessage.messageId(IdUtil.getSnowflakeNextIdStr());
                reportPropertyMessage.addProperty("time", time);
                reportPropertyMessage.timestamp();
                messageExporter.export(reportPropertyMessage);
                log.info("id为:{}的用传设备上传了消息,{}", sourceAddress.replace(":", ""), time);
            }
        }
    }

    @Override
    public void encode(OperatorSupplier supplier, DeviceMessage<?> message, MessageExporter<ProtocolMessage<?>> messageExporter) {

    }

    private static byte[] ackResponse(byte[] reqBytes) {
        // 响应
        byte[] resBytes = new byte[30];
        // 复制信息
        System.arraycopy(reqBytes, 0, resBytes, 0, 26);
        // 地址互换
        System.arraycopy(reqBytes, 12, resBytes, 18, 6);
        System.arraycopy(reqBytes, 18, resBytes, 12, 6);
        // 命令字节改为确认
        resBytes[26] = 3;
        // 结束符
        resBytes[28] = 35;
        resBytes[29] = 35;

        // 需要计算校验和的范围
        byte[] needCheckBytes = Arrays.copyOfRange(resBytes, PacketElement.HEADER.getLen(),
                resBytes.length - PacketElement.VERIFY.getLen() - PacketElement.FOOTER.getLen());
        // 待校验位长度
        byte b = AsciiUtil.sumCheck(needCheckBytes, PacketElement.VERIFY.getLen())[0];
        // 修改校验和
        resBytes[27] = b;
        return resBytes;
    }

    public static void main(String[] args) {
  /*      String s = "40403B240101371D0A060C180" +
                "10000000000" +
                "01000000000" +
                "0300002CE01010127" +
                "8008AD06" +
                "2000" +
                "20202020202020202020202020202020202020202020202020202020202020371D0A060C18D82323"; // 结束符*/
        String s = "4040220001012B2D08020C1801000000000001000000000030000202010101278008AD0641002020202020202020202020202020202020202020202020202020202020202029200F1B0B18FC2323";
        byte[] bytes1 = AsciiUtil.hexString2Bytes(s);
        // 使用工具类解析
        try {
            Map<String, Object> map = new GB26875Mapper().readValue(bytes1, Map.class);
            Map<String, Object> data = (Map<String, Object>) map.get("data");
            log.info("GB/T26875解析data数据:{}", data);
            ArrayList<String> strings = (ArrayList<String>) data.get("msgData");
            log.info("GB/T26875解析msgData数据:{}", strings);
//            exporterMessage(map, null);
        } catch (IOException | GB26875Exception e) {
            throw new RuntimeException(e);
        }
        byte[] bytes2 = ackResponse(bytes1);
        log.info("GB/T26875响应数据:{}", AsciiUtil.bytes2HexString(bytes2));
    }
}